package com.diuse.config;

import com.diuse.config.communicate.HeartBeatDo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 单例模式，配置服务类
 * Created by carey on 2016/11/19 0019.
 */
public class Server {

    private static Logger logger = LoggerFactory.getLogger(Server.class);


    private final int port = 8888;
    private volatile boolean running = false;
    private final long receiveTimeDelay = 3000;
    private static ConcurrentHashMap<Class, ObjectAction> actionMapping = new ConcurrentHashMap<Class, ObjectAction>();
    private Thread connWatchDog;

    private static Server server;

    //增加处理类映射关系
    static {
        //心跳对象映射
        actionMapping.put(HeartBeatDo.class, new HeartBeatAction());
    }

    private Server() {

    }


    public static Server getInstance() {
        if (null != server) {
            return server;
        }
        synchronized (Server.class) {
            if (null != server) {
                return server;
            }
            server = new Server();
            return server;
        }
    }

    public void start() {
        if (running)
            return;
        running = true;
        registerShutdown();
        connWatchDog = new Thread(new ConnWatchDog());
        connWatchDog.start();
    }

    public void stop() {
        if (running)
            running = false;
        if (connWatchDog != null)
            connWatchDog.stop();
    }

    /**
     * 是否正在运行
     * @return
     */
    public boolean isRunning(){
        return running;
    }
    private void registerShutdown() {
        logger.info("注册jvm退出钩子");
        Runtime.getRuntime().addShutdownHook(new Thread(new Cleaner()));
    }




    /**
     * 要处理客户端发来的对象，并返回一个对象，可实现该接口。
     */
    public interface ObjectAction {
        Object doAction(Object rev);
    }

    /**
     * 处理心跳的类
     */
    public static final class HeartBeatAction implements ObjectAction {
        public Object doAction(Object rev) {
            System.out.println("处理并返回：" + rev);
            return rev;
        }
    }


    /**
     * jvm退出时执行的类
     */
    class Cleaner implements Runnable {

        public void run() {

            Server.this.stop();
        }

    }


    class ConnWatchDog implements Runnable {
        public void run() {
            try {
                ServerSocket ss = new ServerSocket(port, 5);
                while (running) {
                    Socket s = ss.accept();
                  new Thread(new SocketAction(s)).start();

                }
            } catch (IOException e) {
                logger.error("接受长连接的serversocket异常,", e);
                Server.this.stop();
            }

        }
    }

    class SocketAction implements Runnable {
        Socket s;
        boolean run = true;
        long lastReceiveTime = System.currentTimeMillis();

        public SocketAction(Socket s) {
            this.s = s;
        }

        public void run() {
            int i = 0;
            while (running && run) {
                if (System.currentTimeMillis() - lastReceiveTime > receiveTimeDelay) {
                    overThis();
                } else {
                    try {
                        InputStream in = s.getInputStream();
                        if (in.available() > 0) {
                            i++;
                            ObjectInputStream ois = new ObjectInputStream(in);
                            Object obj = ois.readObject();
                            lastReceiveTime = System.currentTimeMillis();
                            if (obj instanceof HeartBeatDo) {
                                ClientManager.getInstance().addClient((HeartBeatDo)obj,s);
                                return;
                            }
                        } else {
                            Thread.sleep(10);
                        }
                    } catch (Exception e) {
                        e.printStackTrace();
                        overThis();
                    }
                }
            }
        }

        private void overThis() {
            if (run)
                run = false;
            if (s != null) {
                try {
                    s.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            System.out.println("关闭：" + s.getRemoteSocketAddress());
        }

    }


}
